#include "StdAfx.h"
#include "MyActiveObject.h"
#include "MyPayload.h"
#include "TypeIds.h"
#include "DefaultConfig.h"

namespace CO { namespace MyGroupNamespace { namespace MyPackageNamespace {

MyActiveObject::MyActiveObject(void) :
	//
	// Initialize Base class.
	//
	ActiveObject(PORT_COUNT,
		SpiFoundation::RoomFW::ActiveObject::PortPriorityArray(&PortPriorities[0], &PortPriorities[PortPrioritiesSize])),
	//
	// TODO:  Initialize attributes.
	//
	messageHandler_(),
	myConfigValue_(0)	// TODO:  Initialize attributes to default!
{
}

MyActiveObject::~MyActiveObject(void)
{
}

bool MyActiveObject::initialize(SpiFoundation::Configuration::ConfigKey& configRoot)
{
	//
	// TODO:  Initialize attributes with configuration settings.  Get key and value
	//		  will create if they don't exist, so be sure everyone uses the same defines
	//		  to avoid spelling errors!
	//
	configRoot.getValue_T(CFG_VAL_PATH_MyIntValue, myConfigValue_);

	//
	// TODO: Instantiate message handler.  Maybe real or sim based on config value.
	//
	messageHandler_.reset(new MyMessageHandler(this));
	this->clearMessageHandlers();
	this->mapMessageHandler(PORT_MY_PORT_1, messageHandler_);
	this->mapMessageHandler(PORT_MY_PORT_2, messageHandler_);

	return true;
}

SpiFoundation::RoomFW::ObjectId MyActiveObject::getObjectId(void) const
{
	//
	// TODO:  Return a unique id for your object.
	//
	return OID_MY_ACTIVE_OBJECT_ID;
}

const char* MyActiveObject::getObjectName(void) const
{
	//
	// TODO:  Add text for your object name for debugging.
	//
	return "MyActiveObject";
}

void MyActiveObject::handle(SpiFoundation::RoomFW::RoomMessageSP message)
{
	//
	// Catch all exceptions here.  Any that escape will result in the thread exiting.
	//
	try
	{
		//
		// TODO:  Handle message for each port.
		//
		switch (message->portIndex().port())
		{
		case PORT_SYSTEM:
			{
				//
				// TODO:  Handle system messages.
				//
				switch (message->messageID())
				{
				case SystemManagerProtocol::I_AM_READY:
					{
						//
						// TODO:  Begin collaborative initialization.
						//
						this->sendMessage(message->portIndex(), MyProtocol::I_AM_READY_ACK);
					}
					break;
				//case Protocol::SystemManagerProtocol::UPDATE_CONFIG:
				//	{
				//		Protocol::ConfigKeyPayloadSP payload =
				//			::boost::dynamic_pointer_cast<Protocol::ConfigKeyPayload, SpiFoundation::RoomFW::IPayload>(message->payload());
				//		ASSERT(0 != payload);
				//		SpiFoundation::Configuration::ConfigKey& configRoot = payload->valueRef();
				//		//
				//		// TODO:  Apply updated configuration settings.
				//		//
				//	}
				//	break;
				default:
					ASSERT(false);
					break;
				}
			}
			break;
		case PORT_MY_PORT_1: // Test default message handler.
			{
				switch (message->messageID())
				{
				case MyProtocol::IN_ERROR_1:
					{
						this->sendMessage(PORT_MY_PORT_2, message->messageID());
						throw SpiFoundation::ErrorHandling::BaseError(
							SpiFoundation::ErrorHandling::EID_FND_UNHANDLED_EXCEPTION,
							SpiFoundation::ErrorHandling::ESEVfatal,
							"Fatal Error");
					}
					break;
				case MyProtocol::IN_ERROR_2:
					{
						this->sendMessage(PORT_MY_PORT_2, message->messageID());
						throw std::runtime_error("Fatal Exception");
					}
					break;
				case MyProtocol::IN_ERROR_3:
					{
						this->sendMessage(PORT_MY_PORT_2, message->messageID());
						int* i = 0;
						++(*i);
					}
					break;
				case MyProtocol::IN_ERROR_4:
					{
						this->sendMessage(PORT_MY_PORT_2, message->messageID());
						this->setTimer(0);
					}
					break;
				case MyProtocol::IN_ERROR_5:
					{
						this->sendMessage(PORT_MY_PORT_2, message->messageID());
						this->put(
							SpiFoundation::RoomFW::RoomMessageSP(
								new SpiFoundation::RoomFW::RoomMessage(
									(timerPortIndex_ + 1), SpiFoundation::RoomFW::INVALID_MESSAGE_ID)));
					}
					break;
				}
			}
			break;
		case PORT_MY_PORT_2: // Test default message handler.
			{
				switch (message->messageID())
				{
				case MyProtocol::OUT_ERROR:
					{
						this->sendMessage(PORT_MY_PORT_1, message->messageID(), message->releasePayload());
					}
					break;
				}
			}
			break;
		case PORT_MY_PORT_3: // Handle I_AM_READY here for ActiveObjectTestSuite.
			{
				//
				// TODO:  Handle system messages.
				//
				switch (message->messageID())
				{
				case MyProtocol::I_AM_READY:
					{
						//
						// TODO:  Begin collaborative initialization.
						//
						message->reply(MyProtocol::I_AM_READY_ACK);
					}
					break;
				default:
					ASSERT(false);
					break;
				}
			}
			break;
		case PORT_TIMER: // Handle timer messages.
			{
				SpiFoundation::RoomFW::RoomTimer::TimerId timerId = message->messageID();
				ASSERT(SpiFoundation::RoomFW::RoomTimer::InvalidTimerId != timerId);
				//
				// TODO:  Handle timer id.
				//
				// Test error handling.
				throw std::runtime_error("Timer Error");
			}
			break;
		default:
			//ASSERT(FALSE); // No more ports!
			// Test error handling.
			throw std::runtime_error("Unexpected Message Error");
		}
	}
	//
	// TODO: Catch specific errors and handle them correctly.
	//
	DEFAULT_MSG_CATCH_BLOCKS(this, PORT_SYSTEM, message, PORT_MY_PORT_1, MyProtocol::OUT_ERROR)
}

void MyActiveObject::onError(SpiFoundation::ErrorHandling::IError& e)
{
	//
	// TODO: Remove logging and Handle the error.  DEFAULT_HSM_CATCH_BLOCKS already logs.
	//
	G_LOG_1_ERROR("MyActiveObject::onError(%s)", e.what());
}

void MyActiveObject::onException(std::exception& e)
{
	//
	// TODO: Remove logging and Handle the error.  DEFAULT_HSM_CATCH_BLOCKS already logs.
	//
	G_LOG_1_ERROR("MyActiveObject::onException(%s)", e.what());
}

void MyActiveObject::onCatchAllException()
{
	//
	// TODO: Remove logging and Handle the error.  DEFAULT_HSM_CATCH_BLOCKS already logs.
	//
	G_LOG_0_ERROR("MyActiveObject::onCatchAllException()");
}

}}} // End namespace
